package com.hui.platform.falseworkapi.common.security.jwt;

import com.hui.platform.falseworkapi.common.security.constant.JwtProperties;
import com.hui.platform.falseworkapi.common.security.utils.JwtTokenUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * JWT过滤器，作用：用于认证请求头的token信息
 *
 * @author Peng
 */
@Slf4j
public class JwtAuthorizationTokenFilter extends OncePerRequestFilter {

    private final UserDetailsService userDetailsService;

    private final JwtTokenUtil jwtTokenUtil;

    private final JwtProperties jwtProperties;

    private final MessageSource messageSource;

    private final JsonAuthenticationEntryPoint jsonAuthenticationEntryPoint;

    public JwtAuthorizationTokenFilter(UserDetailsService userDetailsService,
                                       JwtTokenUtil jwtTokenUtil,
                                       JwtProperties jwtProperties,
                                       MessageSource messageSource) {
        this.userDetailsService = userDetailsService;
        this.jwtTokenUtil = jwtTokenUtil;
        this.jwtProperties = jwtProperties;
        this.messageSource = messageSource;
        //初始化未认证处理器
        this.jsonAuthenticationEntryPoint = new JsonAuthenticationEntryPoint(this.messageSource);
    }

    /**
     * 请求过滤方法
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {

        //基本判断值
        String tokenHeader = jwtProperties.getTokenHeader();
        String tokenStartHead = jwtProperties.getTokenStartHead();

        //获取请求头的token信息
        final String requestHeader = request.getHeader(tokenHeader);

        //检查是否带有Token,没有则跳过Token检查
        if (StringUtils.hasText(requestHeader) && requestHeader.startsWith(tokenStartHead)) {

            //认证的Token
            String authToken = requestHeader.substring(tokenStartHead.length());

            //解析和验证Token
            String username = null;
            try {
                username = jwtTokenUtil.getUsernameFromToken(authToken);
            } catch (Exception e) {
                handleException(response, e.getMessage());
            }

            log.info("checking username:{}", username);

            //判断用户名是否正常
            if (!StringUtils.hasText(username)){
                handleException(response, "用户名不正常");
                return;
            }

            UserDetails user = null;
            //判断认证信息是否为空，没有则注入Authentication
            if (SecurityContextHolder.getContext().getAuthentication() == null) {
                try {
                    //查找UserDetails信息，用户异常UsernameNotFoundException
                    user = userDetailsService.loadUserByUsername(username);
                }catch (UsernameNotFoundException e){
                    handleException(response, "用户不存在或者已删除");
                    return;
                }catch (Exception e){
                    log.warn("unknown user execption", e);
                    handleException(response, e.getLocalizedMessage());
                    return;
                }
                //用户细节判断
                if (user == null){
                    handleException(response, "用户不存在");
                    return;
                }

                //设置Authentication
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);

                log.info("authenticated user:{}", username);

            } else {
                //user可能不存在
                user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

                if (!jwtTokenUtil.validateToken(authToken, user)){
                    //校验Token和用户信息 Authentication存在的时候校验
                    handleException(response, "非法Token和用户信息");
                }

            }

        }
        //执行下一个过滤器
        chain.doFilter(request, response);
    }

    /**
     * 响应前台异常
     *
     * @param response 响应对象
     * @param errorMsg 错误信息
     */
    @SneakyThrows
    private void handleException(HttpServletResponse response, String errorMsg) {
        try {
            //未认证异常处理
            AuthenticationException authException = new AuthenticationException(errorMsg) {};
            jsonAuthenticationEntryPoint.commence(null, response, authException);
        }catch (IOException e){
            log.warn("unknown IOExecption", e);
        }
    }

}
